from spice.circuit import Circuit
import traceback
from public import getBOMains, Bom, to_bom_map, get_exdb_map


def _getPinMap(circuit: Circuit)->tuple[dict,dict]:
    cls_map = {}
    cls_num_map = {}
    for component in circuit.component_map.values():
        if component.name.startswith(('TP','V')): continue
        cls_map[component.class_] = cls_map.get(component.class_, 0) + 1
        cls_num_map[component.class_] = cls_num_map.get(component.class_, 0) + component.pin_num
    return cls_map, cls_num_map
    
def _getValue(name:str, value:str, pcb_footprint:str|None)->str:
    vs = sorted(value.replace('，','/').replace(' ','').replace(',','/').split('/'))
    return f'{name} - {"/".join(vs)}'+(f'  PCB Footprint: {pcb_footprint}' if pcb_footprint else '')
    
def bom_check_main(path):
    try:
        bom_map = to_bom_map(path)
        main_map:dict[str, Bom] = getBOMains()
        exdb = get_exdb_map()
        if isinstance(main_map, str): raise ValueError(main_map)
        errs = []
        for key, row in bom_map.items():
            if not row.is_check: continue
            main_row = main_map.get(key)
            if not main_row: 
                errs.append(f'BOM文件物料编码-{key} 未在总表中发现')
                continue
            localv = _getValue(row.name, row.info, row.pcb_footprint)
            # 存在字段就进行封装库对比
            mainv = _getValue(main_row.name, main_row.info, exdb.get(key) if row.pcb_footprint else None)
            if mainv!=localv: errs.append(f'BOM文件物料编码-{key} 与总表不一致\n总表: {mainv}\nBOM: {localv}')
        if errs: raise ValueError('\n\n'.join(errs))
        result = '✅BOM文件与总表信息校验成功'
    except Exception as e:
         result =f'🚫BOM文件与总表信息校验失败\n{e}'
    return result
    
def bom_check_net(circuit: Circuit, path):
    if not circuit: return '未上传网表信息'
    try:
        bom_map = to_bom_map(path)
        cls_map, cls_num_map = _getPinMap(circuit)
        cls_num = sum(n for n in cls_map.values())
        bom_num = int(sum(row.num for row in bom_map.values() if row.num and row.pin_num))
        if cls_num != bom_num: raise ValueError(f'BOM文件与网表有PIN元器件数量不一致\n网表总数: {cls_num}\n网表详细计数: {cls_map}\nBOM文件总数: {bom_num}')
        pin_num = sum(n for n in cls_num_map.values())
        bom_pin_num = int(sum(row.all_pin_num for row in bom_map.values() if row.all_pin_num))
        if pin_num != bom_pin_num: raise ValueError(f'BOM文件与网表PIN总数不一致\n网表PIN总数: {pin_num}\n网表详细类型PIN计数: {cls_num_map}\nBOM文件PIN总数: {bom_pin_num}')
        result = '✅BOM文件与网表PIN数校验正确'
    except ValueError as e:
        result= f'🚫BOM文件与网表PIN数校验失败\n{e}'
    except Exception as e:
        traceback.print_exc()
        result= f'🚫BOM文件与网表PIN数校验失败\n{e}'
    return result
